From d682aed55088a49e590b5e0e3fdb6ebb0d044d07 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jonas=20=C3=85dahl?= Date: Thu, 27 Aug 2015 14:59:45 +0800 Subject: [PATCH] wayland: Don't broadcast selection owner changes When receiving a selection or when a drag icon enter a window, it was targeted at a specific window. Lets emit the GDK_OWNER_CHANGE event only for this window, instead of broadcasting. Broadcasting has some nasty side effects. For example, if there was n GdkWindows, and one would for every "owner-change" signal handler receive n signals about the owner being changed. An example of where this went a bit out of hand was gnome-terminal, which added one listener per terminal window. This meant that if one had m number of terminal windows, each time any one would loose or gain keyboard focus, O(m^2) owner-change events would be emitted. https://bugzilla.gnome.org/show_bug.cgi?id=754158 --- gdk/wayland/gdkdevice-wayland.c | 39 +++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 50b3ffc3ff..792de22c37 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -75,6 +75,7 @@ struct _GdkWaylandDeviceData GdkModifierType button_modifiers; GdkWindow *pointer_focus; GdkWindow *keyboard_focus; + GdkAtom pending_selection; struct wl_data_device *data_device; double surface_x, surface_y; uint32_t time; @@ -669,21 +670,6 @@ emit_selection_owner_change (GdkWindow *window, gdk_event_free (event); } -static void -emit_selection_owner_change_forall (GdkAtom atom) -{ - GdkDisplay *display = gdk_display_get_default (); - GdkScreen *screen = GDK_WAYLAND_DISPLAY (display)->screen; - GList *windows, *l; - - windows = gdk_screen_get_toplevel_windows (screen); - - for (l = windows; l; l = l->next) - emit_selection_owner_change (l->data, atom); - - g_list_free (windows); -} - static void data_device_data_offer (void *data, struct wl_data_device *data_device, @@ -744,7 +730,8 @@ data_device_enter (void *data, GDK_CURRENT_TIME); gdk_wayland_selection_set_offer (device->display, selection, offer); - emit_selection_owner_change_forall (selection); + + emit_selection_owner_change (dest_window, selection); } static void @@ -827,7 +814,16 @@ data_device_selection (void *data, selection = gdk_atom_intern_static_string ("CLIPBOARD"); gdk_wayland_selection_set_offer (device->display, selection, offer); - emit_selection_owner_change_forall (selection); + + /* If we already have keyboard focus, the selection was targeted at the + * focused surface. If we don't we will receive keyboard focus directly after + * this, so lets wait and find out what window will get the focus before + * emitting the owner-changed event. + */ + if (device->keyboard_focus) + emit_selection_owner_change (device->keyboard_focus, selection); + else + device->pending_selection = selection; } static const struct wl_data_device_listener data_device_listener = { @@ -1163,6 +1159,13 @@ keyboard_handle_enter (void *data, device, device->keyboard_focus)); _gdk_wayland_display_deliver_event (device->display, event); + + if (device->pending_selection != GDK_NONE) + { + emit_selection_owner_change (device->keyboard_focus, + device->pending_selection); + device->pending_selection = GDK_NONE; + } } static void stop_key_repeat (GdkWaylandDeviceData *device); @@ -2231,6 +2234,8 @@ _gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager, device->foreign_dnd_window = create_foreign_dnd_window (display); device->wl_seat = wl_seat; + device->pending_selection = GDK_NONE; + wl_seat_add_listener (device->wl_seat, &seat_listener, device); wl_seat_set_user_data (device->wl_seat, device); -- 2.30.2